package router

import (
	"github.com/gin-gonic/gin"
)

type (
	ApiResponse struct {
		Error int    `json:"error"`
		Msg   string `json:"msg"`
		Data  any    `json:"data"`
	}
	IHandler interface {
		Handle(*gin.Context) (any, error)
	}
)

// ---------------------------------------------------------------------------------------------------------------------
/**
第一种方式：只需要绑定一个方法作为参数，func(context *gin.Context, req any ) (resp any, err error)
req 请求参数结构体，包含参数验证规则
resp 为任意响应数据，可以为空
err 为业务中出现的错误

type Q struct {
	B string `uri:"b"`
	A string `form:"a"`
}

type P struct {
	ID int `json:"id"`
}

func Test(context *gin.Context, q *Q) (p P, err error) {
	p.ID = 1
	return
}

然后与在路由中进行注册即可:

r.GET("/test/:b", Bind(Test))
**/

// Bind 路由绑定Request和Response对象，自动对参数进行验证
func Bind[Request any, Response any](f func(*gin.Context, *Request) (Response, error)) func(ctx *gin.Context) {
	return func(ctx *gin.Context) {
		var req = new(Request)
		//URI参数
		if err := ctx.ShouldBindUri(req); err != nil {
			//uri参数验证错误
			return
		}
		//BODY参数，自动决定是FORM还是JSON
		if err := ctx.ShouldBind(req); err != nil {
			//参数验证错误
			return
		}
		if resp, err := f(ctx, req); err != nil {
			ctx.JSON(200, ApiResponse{0, err.Error(), nil})
		} else {
			ctx.JSON(200, ApiResponse{0, "ok", resp})
		}
	}
}

// ---------------------------------------------------------------------------------------------------------------------
/**
第二种方法：只需要传入实现了 IHandler 的结构体即可实现业务逻辑，所以只需要创建一个结构体像这样：

type Q struct {
	B string `uri:"b"`
	A string `form:"a"`
}

func (q *Q) Handle(*gin.Context) (any, error) {
	return svc.xxxxxxx(q.B,q.A)
}
然后与在路由中进行注册即可:

r.GET("/test/:b", Auto(new(Q)))
**/

// Bind 路由绑定Request和Response对象，自动对参数进行验证
func Auto[Handler IHandler](req Handler) func(ctx *gin.Context) {
	return func(ctx *gin.Context) {
		//URI参数
		if err := ctx.ShouldBindUri(req); err != nil {
			//uri参数验证错误
			return
		}
		//BODY参数，自动决定是FORM还是JSON
		if err := ctx.ShouldBind(req); err != nil {
			//参数验证错误
			return
		}
		if resp, err := req.Handle(ctx); err != nil {
			ctx.JSON(200, ApiResponse{0, err.Error(), nil})
		} else {
			ctx.JSON(200, ApiResponse{0, "ok", resp})
		}
	}
}
